package sm.hibernate;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;

import sm.codec.type.NullValue;
import sm.dbdict.DBDictUtil;
import sm.dbdict.def.DBDict;
import sm.dbdict.def.Field;
import sm.def.Type;
import sm.util.SMMap;
import sm.util.Util;

public class DAMUtil {

	public static int getTypeFromDef(Object type) {
		int number = 0;
		if (type instanceof List) {
			number = Type.ARRAY_TYPE;
		} else if (type instanceof Map) {
			number = Type.STRUCTURE_TYPE;
		} else if (type instanceof Double) {
			number = ((Double) type).intValue();
		}
		return number;
	}

	public static int getTypeFromValue(Object value) {
		int number = 0;
		if (value instanceof List) {
			number = Type.ARRAY_TYPE;
		} else if (value instanceof Map) {
			number = Type.STRUCTURE_TYPE;
		} else {
			number = Type.getTypeNumber(value);
		}
		return number;
	}

	/**
	 * batch get value by field path
	 * 
	 * @param values
	 * @param fieldPaths
	 * @return
	 */
	public static Object[] getValues(SMMap values, String[] fieldPaths) {
		Object[] fieldValues = new Object[fieldPaths.length];
		for (int i = 0; i < fieldPaths.length; i++) {
			fieldValues[i] = values.get(fieldPaths[i]);
		}
		return fieldValues;
	}

	/**
	 * batch set value
	 * 
	 * @param values
	 * @param fieldPaths
	 * @param fieldValues
	 */
	public static void setValues(SMMap values, String[] fieldPaths,
			Object[] fieldValues) {
		for (int i = 0; i < fieldPaths.length; i++) {
			values.put(fieldPaths[i], fieldValues[i]);
		}
	}

	/**
	 * construct joins
	 * 
	 * @param dbdict
	 * @return
	 */
	public static String[] getJoinedArrayPaths(DBDict dbdict) {
		List<Field> joinedArrays = DBDictUtil.getAllJoinedArrays(dbdict);
		int size = joinedArrays.size();
		String[] joinedArrayPaths = new String[size];

		for (int i = 0; i < size; i++) {
			Field field = joinedArrays.get(i);
			String radPath = DBDictUtil.getFieldPath(field);
			joinedArrayPaths[i] = Util.radFieldPathToJava(radPath);
		}
		return joinedArrayPaths;
	}

	/**
	 * get the field path to be compared
	 * 
	 * @param dbdict
	 * @return
	 */
	public static List<String> getFieldValuePath(DBDict dbdict) {
		List<String> fieldValuePaths = new ArrayList<String>();
		List<Field> fields = dbdict.getField();
		int size = fields.size();
		int curLevel = 0;
		int curIdx = 0;

		// skip descriptor
		for (int i = 1; i < size; i++) {
			Field field = fields.get(i);

			if (field.getType() == Type.STRUCTURE_TYPE) {
				// skip structure
				continue;
			}

			int fieldLevel = field.getLevel();
			int fieldIdx = field.getIndex();
			if (fieldLevel == curLevel && fieldIdx == curIdx) {
				// skip alias
				continue;
			} else {
				curLevel = fieldLevel;
				curIdx = fieldIdx;
			}

			String fieldPath = DBDictUtil.getFieldPath(field);
			String javaFieldPath = Util.radFieldPathToJava(fieldPath);
			fieldValuePaths.add(javaFieldPath);

			if (field.getType() == Type.ARRAY_TYPE) {
				// skip array's sub fields
				List<Field> subFields = DBDictUtil.getSubFields(fields, field);
				i += subFields.size();
			}
		}

		return fieldValuePaths;
	}

	public static boolean containsNullValue(Object[] values) {
		boolean containsNull = false;
		for (Object value : values) {
			if (value instanceof NullValue || value == null) {
				containsNull = true;
				break;
			}
		}
		return containsNull;
	}

	public static List<SMMap> getDatasByKey(HibernateTemplate template,
			final String entityName, final String[] keyPaths,
			final Object[] keyValues) {
		return (List<SMMap>) template.execute(new HibernateCallback() {
			@Override
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Criteria criteria = session.createCriteria(entityName);
				for (int i = 0; i < keyPaths.length; i++) {
					String keyPath = keyPaths[i];
					Object keyValue = keyValues[i];
					if (keyValue instanceof NullValue || keyValue == null) {
						criteria.add(Restrictions.isNull(keyPath));
					} else {
						criteria.add(Restrictions.eq(keyPath, keyValue));
					}
				}
				return criteria.list();
			}
		});
	}
}
